﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

//TODO: test

using Direction = LowLevelGraphics.Filter.Contours.Direction;

namespace LowLevelGraphics.Filter.Contours
{

  
    /// <summary>
    /// 
    /// </summary>
    public class Path
    {
        // statics
        
        private static double ADJ_LEN = Math.Sqrt(2.0) / 2.0 - 1;

        // fields

        private Direction[] m_aDirection = null;

        private List<Direction> m_aDirectionList = new List<Direction>();

        private double m_dLength = 0;

        private int m_nOriginX = 0;

        private int m_nOriginY = 0;

        private int m_nTerminalX = 0;

        private int m_nTerminalY = 0;

        // constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Path"/> class.
        /// </summary>
        /// <param name="that">The that.</param>
        /// <param name="deltaX">The delta X.</param>
        /// <param name="deltaY">The delta Y.</param>
        private Path(Path that, int deltaX, int deltaY)
        {
            this.m_aDirection = that.m_aDirection;
            this.m_aDirectionList = that.m_aDirectionList;
            this.m_dLength = that.m_dLength;
            this.m_nOriginX = that.m_nOriginX + deltaX;
            this.m_nOriginY = that.m_nOriginY + deltaY;
            this.m_nTerminalX = that.m_nTerminalX + deltaX;
            this.m_nTerminalY = that.m_nTerminalY + deltaY;
        }

        /// <summary>
        /// Directions to walk to create the path
        /// </summary>
        public List<Direction> Directions
        {
            get { return m_aDirectionList; }
        }

        /// <summary>
        /// sets the Origin
        /// </summary>
        public Point Origin
        {
            get { return new Point(m_nOriginX, m_nOriginY); }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_path"></param>
        internal Path(Path _path)
        {
            this.m_aDirection = (Direction[])_path.m_aDirection.Clone();

            Direction[] aDirectionList = new Direction[this.m_aDirectionList.Count];
            _path.m_aDirectionList.CopyTo(aDirectionList); //Collections.unmodifiableList(Arrays.asList(directions));
            this.m_aDirectionList.AddRange(aDirectionList);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Path"/> class.
        /// </summary>
        /// <param name="_nStartX">The start X.</param>
        /// <param name="_nStartY">The start Y.</param>
        /// <param name="directions">The directions.</param>
        public Path(int _nStartX, int _nStartY, Direction[] directions)
        {
            this.m_nOriginX = _nStartX;
            this.m_nOriginY = _nStartY;
            this.m_aDirection = (Direction[])directions.Clone();
            this.m_aDirectionList.AddRange(directions); //Collections.unmodifiableList(Arrays.asList(directions));

            int nEndX = _nStartX;
            int nEndY = _nStartY;
            int nDiagonals = 0;
            foreach (Direction direction in directions) 
            {
                nEndX += direction.screenX;
                nEndY += direction.screenY;
                if (direction.screenX != 0 && direction.screenY != 0) 
                {
                    nDiagonals++;
                }
            }

            this.m_nTerminalX = nEndX;
            this.m_nTerminalY = nEndY;
            this.m_dLength = directions.Length + nDiagonals * ADJ_LEN;
        }
    }
}
